package com.nulldev.util.web.URLUtils;

import java.net.URL;
import java.util.List;
import java.util.Map;

import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.internal.backport.concurrency9.Maps;
import com.nulldev.util.manage.MarkedForRemoval;
import com.nulldev.util.web.YouTubeExtractor.Qtraxtor.ExtractedSet;
import com.nulldev.util.web.YouTubeExtractor.Qtraxtor.Qtraxtor;
import com.nulldev.util.web.YouTubeExtractor.Qtraxtor.Qtraxtor.FillMode;
import com.nulldev.util.web.YouTubeExtractor.Qtraxtor.Qtraxtor.SplitMode;
import com.nulldev.util.web.legacyURI.LegacyURIUtils;

public class URLQueryParser {

	private static enum Backend {
		@Deprecated
		LEGACY_QUERY,
		@Deprecated
		@MarkedForRemoval(reason = "Qtraxtor will be removed in a future YTE release.", plannedRemovalWhen = "2.3 or 2.2.10")
		QTRAXTOR,
		PARSE_QUERY
	}

	public static enum URLQueryParserOptions {
		PREFER_QTRAXTOR,
		@Deprecated
		PREFER_LEGACY,
		PREFER_LEGACY_IF_ACCEL_V1,
		PREFER_EXPERIMENTAL,
		DISABLE_URL_ACCEL,
		DISABLE_DECODING,
		TREAT_URL_AS_QUERY,
	}

	private static final Backend BACKEND = Backend.PARSE_QUERY;

	@SuppressWarnings("deprecation")
	public static Map<String, String> extract(final String url, final URLQueryParserOptions... options) {
		if (url == null)
			throw new NullPointerException("url == null!");
		else if (url.isEmpty())
			return Maps.of();
		if (ArrayUtils.contains(options, URLQueryParserOptions.PREFER_QTRAXTOR)) {
			final List<ExtractedSet> sets = Qtraxtor.get(url, SplitMode.STANDARD, FillMode.FILL_INTO_SINGLE_SET);
			if (sets.size() == 1)
				return sets.get(0);
			else if (sets.isEmpty())
				return null;
			else
				throw new UnsupportedOperationException("[extract::QTRAXTOR] Multiple sets aren't implemented yet!");
		} else if (ArrayUtils.contains(options, URLQueryParserOptions.PREFER_LEGACY)) {
			return (ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING) ? LegacyURIUtils.queryStringToMap_NoDecode(url)
					: LegacyURIUtils.queryStringToMap(url));
		} else if (ArrayUtils.contains(options, URLQueryParserOptions.PREFER_EXPERIMENTAL)) {
			return URLUtils.parseQuery(
					(ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_URL_ACCEL) ? URLUtils.parseURL_NoAccel(url) : URLUtils.parseURL(url)),
					!ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING));
		} else if (ArrayUtils.contains(options, URLQueryParserOptions.PREFER_LEGACY_IF_ACCEL_V1)) {
			if (ArrayUtils.contains(options, URLQueryParserOptions.TREAT_URL_AS_QUERY)) {
				return URLUtils.parseQuery(url, !ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING));
			} else if (URLUtils.USE_URL_ACCEL_V2) {
				return URLUtils.parseQuery(
						(ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_URL_ACCEL) ? URLUtils.parseURL_NoAccel(url) : URLUtils.parseURL(url)),
						!ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING));
			} else {
				return (ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING) ? LegacyURIUtils.queryStringToMap_NoDecode(url)
						: LegacyURIUtils.queryStringToMap(url));
			}
		} else {
			switch (BACKEND) {
				case LEGACY_QUERY: {
					return LegacyURIUtils.queryStringToMap(url);
				}
				case PARSE_QUERY: {
					if (ArrayUtils.contains(options, URLQueryParserOptions.TREAT_URL_AS_QUERY)) {
						return URLUtils.parseQuery(url, !ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING));
					} else {
						final URL lurl = (ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_URL_ACCEL) ? URLUtils.parseURL_NoAccel(url)
								: URLUtils.parseURL(url));
						return URLUtils.parseQuery(lurl, !ArrayUtils.contains(options, URLQueryParserOptions.DISABLE_DECODING));
					}
				}
				case QTRAXTOR: {
					final List<ExtractedSet> sets = Qtraxtor.get(url, SplitMode.STANDARD, FillMode.FILL_INTO_SINGLE_SET);
					if (sets.size() == 1)
						return sets.get(0);
					else if (sets.isEmpty())
						return null;
					else
						throw new UnsupportedOperationException("[extract::QTRAXTOR] Multiple sets aren't implemented yet!");
				}
				default:
					throw new UnsupportedOperationException("Unsupported backend: " + BACKEND);
			}
		}
	}
}
